/*
*********************************************************************************************************
*
*	模块名称 : BSP DMA
*
*********************************************************************************************************
*/

#ifndef _BSP_DMA_H_
#define _BSP_DMA_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "stdint.h"
#include "bsp.h"

	/*******************************************************************************
	 * @brief  APP DMA type
	 *******************************************************************************/
	typedef struct
	{
		dma_type *DMAx;						// DMA 模块
		dma_channel_type *channel;			// DMA 数据流
		dmamux_channel_type *mux;			// DMA MUX
		uint16_t ch_num;					// DMA 通道编号
		dmamux_requst_id_sel_type trig_src; // DMA 触发源
		IRQn_Type irqn;						// 中断号
	} app_dma_type;

#ifdef IN_DMA_MOUDLE
#define dma_stream_make(name, dmax, ch, src) \
	const app_dma_type name = {              \
		.DMAx = dmax,                        \
		.channel = dmax##_CHANNEL##ch,       \
		.mux = dmax##MUX_CHANNEL##ch,        \
		.ch_num = ch,                        \
		.trig_src = src,                     \
		.irqn = dmax##_Channel##ch##_IRQn}
#else
#define dma_stream_make(name, dmax, ch, src) \
	extern const app_dma_type name
#endif

	/*******************************************************************************
	 * @brief  APP DMA CONFIG
	 *******************************************************************************/
	dma_stream_make(DMA_U01_RX, DMA1, 1, DMAMUX_DMAREQ_ID_USART1_RX);
	dma_stream_make(DMA_U01_TX, DMA1, 2, DMAMUX_DMAREQ_ID_USART1_TX);

	dma_stream_make(DMA_U02_RX, DMA1, 3, DMAMUX_DMAREQ_ID_USART2_RX);
	dma_stream_make(DMA_U02_TX, DMA1, 4, DMAMUX_DMAREQ_ID_USART2_TX);

	dma_stream_make(DMA_U03_RX, DMA1, 5, DMAMUX_DMAREQ_ID_USART3_RX);
	dma_stream_make(DMA_U03_TX, DMA1, 6, DMAMUX_DMAREQ_ID_USART3_TX);

	dma_stream_make(DMA_ADC, DMA1, 7, DMAMUX_DMAREQ_ID_ADC1);

	/*******************************************************************************
	 * @brief  中断回调注册
	 *******************************************************************************/
	typedef struct
	{
		void (*stream10)(void);
		void (*stream11)(void);
		void (*stream12)(void);
		void (*stream13)(void);
		void (*stream14)(void);
		void (*stream15)(void);
		void (*stream16)(void);
		void (*stream17)(void);
		void (*stream20)(void);
		void (*stream21)(void);
		void (*stream22)(void);
		void (*stream23)(void);
		void (*stream24)(void);
		void (*stream25)(void);
		void (*stream26)(void);
		void (*stream27)(void);
	} dma_it_type;

	extern dma_it_type dma_it;

	/*******************************************************************************
	 * @brief  APP DMA API
	 *******************************************************************************/
	void dma_nvic_set(const app_dma_type *dmax, uint32_t irq_en, void (*callback)(void));

	/*******************************************************************************
	 * @brief  配置
	 *******************************************************************************/
	typedef struct
	{
		uint8_t mem_to_periph;
		uint8_t cycle_mode;
		uint8_t mem_inc, periph_inc;
		uint16_t data_len;
		dma_priority_level_type prio;
		void *mem;
		volatile void *periph;
	} dma_stream_cfg_type;

	void dma_stream_config(const app_dma_type *dmax, dma_stream_cfg_type *cfg);
	/*******************************************************************************
	 * @brief  获取传输完成标志
	 * \param[in] dma
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE uint32_t dma_comp_flag_get(const app_dma_type *dmax)
	{
		int stream = (dmax)->ch_num;
		int bits = 4 * (stream - 1) + 1;

		return ((dmax)->DMAx->sts >> bits) & 1;
	}

	/*******************************************************************************
	 * @brief  清除传输完成标志
	 * \param[in] dma
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE void dma_comp_flag_clr(const app_dma_type *dmax)
	{
		int stream = (dmax)->ch_num;
		int msk = 0x0FUL << 4 * (stream - 1);

		(dmax)->DMAx->clr = msk;
	}

/*******************************************************************************
 * @brief  库接口映射
 * \param[in] dma
 * \retval:  0-No 1-Yes
 *******************************************************************************/
/* 反初始化 */
#define dma_stream_deinit(dmax) dma_reset((dmax)->channel)

/* 判断是否已使能DMA数据流 */
#define is_dma_stream_enable(dmax) (dmax)->channel->ctrl_bit.chen

/* 使能DMA数据流 */
#define dma_stream_enable(dmax) \
	dma_comp_flag_clr(dmax);    \
	dma_channel_enable((dmax)->channel, TRUE)

/* 禁能DMA数据流 */
#define dma_stream_disable(dmax) dma_channel_enable((dmax)->channel, FALSE)

/* 设置DMA数据流RAM地址 */
#define dma_stream_set_mem_addr(dmax, addr) (dmax)->channel->maddr = (addr)

/* 设置DMA数据流外设地址 */
#define dma_stream_set_periph_addr(dmax, addr) (dmax)->channel->paddr = (addr)

/* 设置DMA数据流数据长度 */
#define dma_stream_set_data_len(dmax, len) (dmax)->channel->dtcnt = (len)

/* 获取DMA数据流剩余传输长度 */
#define dma_stream_get_data_len(dmax) (dmax)->channel->dtcnt

/* 使能数据流传输完成中断 */
#define dma_stream_complete_isr_enable(dmax) (dmax)->channel->ctrl_bit.fdtien = 1

#ifdef __cplusplus
}
#endif

#endif
